package main

// 数组 值类型的 值类型 改变副本值不会影响原来，引用类型 改变副本值会改变原来值
func ay() {
	// 定义
	// var 变量 [长度] 类型
	// 变量赋值 超出报错
	// var s [10]string
	// s[0] = "a"
	// fmt.Println(s)

	// 最后一个一必须有,
	// var s = [10]string{
	// 	"a",
	// }
	// fmt.Println(s)

	// s := [10]string{
	// 	"a",
	// }
	// fmt.Println(s)

	// ...初始化有几个值...就有几个长度
	// s := [...]string{
	// 	"a",
	// 	"b",
	// 	"c",
	// }
	// fmt.Println(s)

	// 类型 %T [10]string
	// a := [10]string{
	// 	"a",
	// }
	// fmt.Printf("%T", a)

	// 数组声明的基本数据类如果没赋值 申请空间 使用改基础类型默认值填充。
	// a := [10]bool{}
	// fmt.Print(a[0])

	// 看数组长度可以用len
	// str := [...]string{
	// 	"大",
	// }

	// fmt.Print(len(str))

	// 数组长度定了就定了没法在扩容  扩容需要切片 切片底层也是数组

	// 数组初始化指定下标
	// a := [10]string{
	// 	1: "a",
	// 	4: "d",
	// }
	// fmt.Println(len(a))

	// a := [...]string{
	// 	10: "aa",
	// }
	// fmt.Println(len(a)) // 11

	// 数组循环遍历  for i  for range
	// a := [...]string{
	// 	"大",
	// 	"en",
	// 	"lq",
	// }
	// for i := 0; i < len(a); i++ {
	// 	fmt.Println(a[i])
	// }
	// for k, v := range a {
	// 	fmt.Println(k, v)
	// }

	// 值类型

	// 多纬数组 注意多维数组后面那个不能是...了 推断不出来第二个...推断不出来
	// a := [...][10]string{
	// 	{
	// 		"a",
	// 		"b",
	// 		"c",
	// 	},
	// }
	// fmt.Println(a)

	// 切片是引用类型值
	// 引用类型 b 相当于也指向了a的地址
	// a := []string{"",}
	// b = a

	// a := [3][2]string{
	// 	{""}, {""}, {""},
	// }
	// fmt.Println(a)

	// n 纬数据就无限潜逃
	// a := [3][3][3]string{
	// 	{
	// 		{
	// 			"aa",
	// 		},
	// 	},
	// }

	// fmt.Println(a)
}

// 切片 可变长度 引用类型
func slicess() {
	// []string type  只声明不初始化默认长度是0
	// a := []string{
	// 	"a",
	// }
	// fmt.Printf("%T", a)

	// 声明同数组 没有 [...] 没有 [这里面的长度] 声明切片把数组长度去掉

	// 注意切片声明好了，不能直接赋值没有申请内存空间。
	// var sqx []int
	// sqx[0] = 1
	// fmt.Println(sqx)

	// 如果声明就想用可以赋值初始值或者直接申请内存空间
	// var sqx = []int{ // 初始长度1容量1
	// 	1,
	// }
	// fmt.Print(sqx)

	// 申请内存 len 长度实际用了多大 cap数组真正的容量
	// var sqx = make([]int, 4, 8) // 申请长度4容量8 但是只能赋值在小于4的位置
	// sqx[3] = 1
	// fmt.Print(sqx)

	// 初始化也没有默认值可以用扩容，append扩容算法看原码
	// var s = []int{
	// 	1,
	// 	2,
	// 	3,
	// }
	// var cs []int

	// cs = append(cs, s...)

	// fmt.Print(cs)

	// 指定下标初始化
	// s := []int{
	// 	1:  2,
	// 	10: 21,
	// }

	// fmt.Print(s)

	// golang中 切片只是声明，默认值nil，默认是nil的长度是0。
	// var a []int
	// fmt.Print(a == nil) // true
	// var a = []int{
	// 	1,
	// }
	// fmt.Print(a == nil) // false

	// 切片的循环遍历同数组 for i len, for range

	// 切片的底层是一个数组， 基于数组定义切片
	// a := [...]int{1, 2, 3, 4, 5}
	// bs := a[1:4] // 返回一个切片 : 前后都没数 0-最后    1，4  下标1到下标4-1  len = 3 cap 4 为什么是4 cap 起始位置1到最后 返回值是一个切片 起始到最后[1:]
	// fmt.Println(bs, len(bs), cap(bs))

	// 切片在切片
	// var s = []int{
	// 	1,
	// 	2,
	// 	3,
	// }
	// b := s[:1]
	// fmt.Println(b, len(b), cap(b)) // len = 1 cap = 3

	// 切片的长度容量上面讲了  注意下 数组在切片也好  切片在切片也好 切出来的cap 容量是切之前的那个 也就是赋值右边的那个变量 注意从[n:m] 从n开始到最后m无论多少都无所谓到底 len 实际的个数

	// s := []int{
	// 	1,
	// 	2,
	// 	3,
	// 	4,
	// 	5,
	// 	6,
	// 	7,
	// 	8,
	// 	9,
	// }
	// bs := s[1:]
	// bs1 := bs[:]
	// fmt.Println(cap(bs1)) // 从侧面佐证了用赋值右边的空间

	// 切片本质是对底层数组的封装 切片实际上在数组上的在封装 指针控制而已

	//make 申请内存
	// a := make([]int, 4, 8) // 长度4 容量8 注意下标赋值不能超过3
	// fmt.Println(a)         // 初值根据类型来填充，和声明不赋值有却别的 len 4 cap 8

	// 切片也不能越界赋值只能append来赋值。 下标没办法扩容。  需要扩容的切片 = append(需要扩容的切片 (,,,) or (切片...))

	// 切片只声明 len 0 cap 0 默认 nil

	// 扩容策略看append原码吧，动态扩容 小于1024直接扩容2倍  总之是动态的有时候2倍。

	// 切片的copy
	// a := make([]int, 0, 0)
	// b := []int{1, 2, 3, 4}
	// a = append(a, b...)
	// fmt.Println(a)

	// 或者使用copy
	// a := make([]int, 5) // !!!注意长度必须可以放的下复制的切片 如果复制到的空间不够就扔了。
	// b := []int{
	// 	1, 2, 3, 4, 5,
	// }
	// copy(a, b)
	// fmt.Println(a)

	// 删除切片用[:]来跳过你想删除的元素 append在和起来

	// rune 存储的可能是unicode编码或者是ascii码

	// byte 存储的是ascii码

	// 排序 sort
	// 升序
	// s := []int{10, 2, 3, 4, 5, 6, 7}
	// sort.Ints(s) // 排序int
	// // sort.Float64s() float
	// // sort.Strings() 字符串排序注意是ascii排序
	// fmt.Println(s)

	// 倒序
	// s := []int{10, 2, 3, 4, 5, 6, 7}
	// // fmt.Println(s)
	// sort.Sort(sort.Reverse(sort.IntSlice(s)))
	// fmt.Println(s)
	// sort.StringSlice
	// sort.Float64Slice

}

// map 引用类型
func maps() {
	// 默认值nil
	// var a map[string]string

	// fmt.Println(a == nil)

	// 如果没开辟空间，或者初始化没法使用
	// var a map[string]string
	// a["a"] = "12"
	// fmt.Println(a)

	// 初始化复制 最后一个元素的,要带着
	// var a = map[string]string{xxx}
	// a := map[string]string{
	// 	"a": "1",
	// }
	// a["d"] = "abc"
	// fmt.Println(a)

	// 申请内存空间
	// var a = make(map[string]string) // 长度可以指定也可以不指定
	// a["a"] = "admin"
	// a["b"] = "istrator"
	// fmt.Println(a)

	// for range 来遍历map for  key,v := range maps{}

	// 查看map的属性是否存在
	// var a = make(map[string]string)
	// data, ok := a["username"] // 返回2个值ok可以判断是否存在 false不存在 true存在
	// a["username"] = "3344"
	// data_n, ok_n := a["username"]
	// fmt.Println(data, ok, data_n, ok_n) //  false 3344 true

	// 删除map类型数据
	// var a = make(map[string]string)
	// a["username"] = "3344"
	// // delete(map对象，key)
	// delete(a, "username")
	// fmt.Println(a)

	// 元素为切片类型的map
	// a := map[string][]string{
	// 	"test": []string{
	// 		"a",
	// 		"b",
	// 		"c",
	// 	},
	// }
	// fmt.Println(a)

	// 切片里面装map
	// a := make([]map[string]string, 4, 4) // 用空map去做的填充
	// if a[0] == nil {                     // true
	// 	a[0] = make(map[string]string)
	// 	a[0]["id"] = "aaa"
	// }
	// fmt.Println(a)
	// 用双层循环遍历

	// map排序 先for range拿出所有的key 进切片 然后sort排序 然后遍历排序后的打印对应的值

}

func main() {
	//ay()
	// slicess()
	maps()
}
